/*
 * KKDirector.h
 *
 *  Created on: 2013-9-7
 *      Author: wh
 */

#ifndef KKDIRECTOR_H_
#define KKDIRECTOR_H_

#include "kaka.h"

USING_NS_CC;

using namespace std;

typedef KKDictionary<std::string, KKScene*> KKSceneDictionary;
class KKDirector: public cocos2d::CCObject,
		public CCTouchDelegate,
		public CCKeypadDelegate {

public:

	static int screenWidth;
	static int screenHeight;

	static bool isDebug;

private:

	static KKDirector* kk_share_director;

	KKFuncDictionary* m_events;
	KKSceneDictionary* m_scenes;

	;CC_SYNTHESIZE(bool,m_enableSoundEffect,EnableSoundEffect)
	;CC_SYNTHESIZE(bool,m_enableMusicEffect,EnableMusicEffect)
	;

protected:
	KKScene * m_scene;

public:
	KKDirector() {
		m_events = new KKFuncDictionary();
		m_scenes = new KKSceneDictionary();
		m_enableSoundEffect = true;
		m_enableMusicEffect = true;
	}
	;

	virtual ~KKDirector() {
		CC_SAFE_DELETE(m_events);
		CC_SAFE_DELETE(m_scenes);
		CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(
				this);
		CCDirector::sharedDirector()->getKeypadDispatcher()->removeDelegate(
				this);
	}
	;

	static const char* getVersion();
	// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
	virtual bool init();

	// there's no 'id' in cpp, so we recommand to return the exactly class pointer
	static CCScene* scene();

	static KKDirector* shareDirector() {
		return kk_share_director;
	}
	;

	void loadProject(const char* projectFile);

	// a selector callback
	virtual void exitApp(CCNode* pSender, void* args);

	virtual void showFocus(CCNode* pSender, void* args);
	virtual void loseFocus(CCNode* pSender, void* args);
	virtual void setSelected(CCNode* pSender, void* args);
	virtual void setUnselected(CCNode* pSender, void* args);
	virtual void showTarget(CCNode* pSender, void* args);
	virtual void hideTarget(CCNode* pSender, void* args);
	virtual void toggleTarget(CCNode* pSender, void* args);
	virtual void fadeOutTarget(CCNode* pSender, void* args);
	virtual void fadeInTarget(CCNode* pSender, void* args);
	virtual void setTargetProperty(CCNode* pSender, void* args);
	virtual void resetTarget(CCNode* pSender, void* args);
	virtual void enableTarget(CCNode* pSender, void* args);
	virtual void disableTarget(CCNode* pSender, void* args);

	KKScene* getCurrentScene() {
		return m_scene;
	}
	;

	void showScene(const char* sceneName, bool push = false,
			KKSceneTransitionMode mode = NONE, ccTime duration = 0.5f) {

		CCLog("show scene %s\n", sceneName);

		KKScene* scene = sceneNamed(sceneName);

		showScene(scene, push, mode, duration);
	}

	void showScene(KKScene* scene, bool push = false,
			KKSceneTransitionMode mode = NONE, ccTime duration = 0.5f) {

		if (scene) {

			KKScene* dirtyScene = NULL;

			dirtyScene = m_scene;

			if (scene != m_scene) {
				m_scene = scene;

				bool newLoad = false;

				if (!scene->getIsLoaded()) {
					newLoad = true;
					scene->loadScene();
				}

				if (dirtyScene) {
					dirtyScene->setIsPush(push);
				}

				CCScene* transitionScene = scene;

				switch (mode) {
				case FADE_IN:
					transitionScene = CCTransitionFade::create(duration, scene);
					break;
				case FLIP_LEFT:
					transitionScene = CCTransitionFlipX::create(duration, scene,
							kCCTransitionOrientationLeftOver);
					break;
				case FLIP_RIGHT:
					transitionScene = CCTransitionFlipX::create(duration, scene,
							kCCTransitionOrientationRightOver);
					break;
				case FLIP_UP:
					transitionScene = CCTransitionFlipY::create(duration, scene,
							kCCTransitionOrientationUpOver);
					break;
				case FLIP_DOWN:
					transitionScene = CCTransitionFlipY::create(duration, scene,
							kCCTransitionOrientationDownOver);
					break;

				case SLIDE_L:
					transitionScene = CCTransitionSlideInL::create(duration,
							scene);
					break;
				case SLIDE_R:
					transitionScene = CCTransitionSlideInR::create(duration,
							scene);
					break;
				case SLIDE_T:
					transitionScene = CCTransitionSlideInT::create(duration,
							scene);
					break;
				case SLIDE_B:
					transitionScene = CCTransitionSlideInB::create(duration,
							scene);
					break;

				case CROSS:

					transitionScene = CCTransitionCrossFade::create(duration,
							scene);

					break;

				case SHRINK_GROW:

					transitionScene = CCTransitionShrinkGrow::create(duration,
							scene);
					break;
				case MOVE_IN_L:
					transitionScene = CCTransitionMoveInL::create(duration,
							scene);
					break;
				case MOVE_IN_R:
					transitionScene = CCTransitionMoveInR::create(duration,
							scene);
					break;
				case MOVE_IN_T:
					transitionScene = CCTransitionMoveInT::create(duration,
							scene);
					break;
				case MOVE_IN_B:
					transitionScene = CCTransitionMoveInB::create(duration,
							scene);
					break;

				case RADIAL_CCW:
					transitionScene = CCTransitionProgressRadialCCW::create(
							duration, scene);
					break;
				case RADIAL_CW:
					transitionScene = CCTransitionProgressRadialCCW::create(
							duration, scene);
					break;

				case PAGE_FORWARD:
					transitionScene = CCTransitionPageTurn::create(duration,
							scene, false);
					break;
				case PAGE_BACK:
					transitionScene = CCTransitionPageTurn::create(duration,
							scene, true);

					break;

				default:
					break;

				}

				if (push) {
					CCDirector::sharedDirector()->pushScene(transitionScene);
				} else {
					CCDirector::sharedDirector()->replaceScene(transitionScene);
				}

			}

		}
	}
	;

	void hideScene(KKScene* scene) {

		CCLog("hide scene %s\n", scene ? scene->getName().c_str() : "empty");

		if (scene == CCDirector::sharedDirector()->getRunningScene()) {

			CCDirector::sharedDirector()->popScene();

			m_scene =
					dynamic_cast<KKScene*>(CCDirector::sharedDirector()->getRunningScene());
		}
	}
	;

	KKScene* sceneNamed(const string sceneName) {
		return m_scenes->objectForKey(sceneName);
	}
	;

	KKLayer* layerNamed(const string layerName,
			bool includeInvisiable = false) {
		return dynamic_cast<KKLayer*>(m_scene->nodeNamed(layerName,
				includeInvisiable));
	}
	;
	KKNode* objectNamed(const string objectName,
			bool includeInvisiable = false) {
		return m_scene->nodeNamed(objectName, includeInvisiable);
	}
	;

	KKNode* findNodeById(const int id) {
		return m_scene->findNodeById(id);
	}
	;

	void executeFunc(CCNode* target, string funcName, void*args = NULL);

	void runStoryboard(string storyboardName, void*args = NULL);

	void pauseStoryboard(string storyboardName, void*args = NULL);

	void resumeStoryboard(string storyboardName, void*args = NULL);

	void stopStoryboard(string storyboardName, void*args = NULL);

	void loadSound(const char* path, bool music);

	void playSound(const char* path, bool music, int loop,
			KKCallback* endCallback = NULL);

	void stopSound(const char* path, bool music);

	void pauseSound(const char* path, bool music);

	void resumeSound(const char* path, bool music);

	void adjustSoundVolumn(const char* path, bool music, float volumn);

	void pause();

	void resume();

	void loadImages(const char* image, ...);

	void onImageLoaded(CCObject * obj);

	virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
	virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);
	virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
	virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);

public:

	void registerEventHandler(std::string eventName, SEL_CallFuncND eventFunc,
			CCObject* target = NULL) {

		KKEventHandler* eventHandler = new KKEventHandler();

		if (target == NULL) {
			target = this;
		}

		eventHandler->target = target;
		eventHandler->selector = eventFunc;
		m_events->removeObjectForKey(eventName);
		m_events->setObject(eventHandler, eventName);
	}
	;

};

#endif /* KKDIRECTOR_H_ */
